package com.free.mini.gateway.utils;


import static cn.hutool.core.util.CharUtil.UNDERLINE;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import lombok.extern.slf4j.Slf4j;

/**
 * Bean 》 Map
 * 驼峰规范属性转下划线
 * 支持递归转换，如属性为JavaBean时
 */
@Slf4j
public class HumpTransformUnderlineUtils {

    private static final String compile = "[A-Z]";

    private HumpTransformUnderlineUtils() {
    }

    public static <T> Map transform(T object) {
        if (object == null) {
            return null;
        }

        Map<String, Object> map = new HashMap<>();
        // 获取实体类所有属性，返回Field数组
        Field[] fields = object.getClass().getDeclaredFields();
        String name = null;
        try {

            for (int i = 0; i < fields.length; i++) {
                // 属性名称
                String fieldName = fields[i].getName();

                // 转换驼峰形式属性名称成下划线风格，获取map的key 例：fieldName 》 field_name
                String transformFieldName = HumpTransformUnderlineUtils.getTransformFieldName(fieldName);
                // map 的 value ，属性的值
                Object FieldValue = null;

                // 将属性的首字符大写，方便构造get，set方法
                name = fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);

                // 获取属性的类型
                String type = fields[i].getGenericType().toString();

                Method m;
                try {
                    m = object.getClass().getMethod("get" + name);
                } catch (Exception e) {
                    log.error("get method :[{}] is error ", name);
                    continue;
                }
                switch (type) {
                    // 如果有需要,可以仿照下面继续进行扩充,再增加对其它类型的判断
                    case "class java.lang.String":
                    case "class java.util.Date":
                    case "class java.lang.Integer":
                    case "class java.lang.Long":
                        // 调用getter方法获取属性值

                        FieldValue = m.invoke(object);
                        break;

                    case "class java.lang.Boolean":
                        FieldValue = m.invoke(object);
                        break;
                    case "class java.math.BigDecimal":
                        // 调用getter方法获取属性值
                        FieldValue = m.invoke(object);
                        if (FieldValue != null) {
                            FieldValue = new BigDecimal(FieldValue + "").doubleValue();
                        }
                        log.info("bigDecimal:{}", FieldValue);
                        break;
                    default:
                        // 属性类型为bean,则递归
                        Object obj = m.invoke(object);
                        FieldValue = HumpTransformUnderlineUtils.transform(obj);
                }
                map.put(transformFieldName, FieldValue);
            }
        } catch (Exception e) {
            // 系统异常
            log.error("HumpTransformUnderlineUtils  name:{} to _ is error : ", name, e);
        }
        return map;
    }

    /**
     * 转换风格 驼峰转下划线 -- 单字段
     *
     * @param fieldName 属性名称
     * @return
     */
    public static String getTransformFieldName(String fieldName) {
        Pattern humpPattern = Pattern.compile(compile);
        Matcher matcher = humpPattern.matcher(lowerFirst(fieldName));
        StringBuffer sb = new StringBuffer();
        while (matcher.find()) {
            matcher.appendReplacement(sb, "_" + matcher.group(0).toLowerCase());
        }
        matcher.appendTail(sb);
        return sb.toString();
    }

    //首字母转小写
    public static String lowerFirst(String fromStr) {
        return fromStr.substring(0, 1).toLowerCase() + fromStr.substring(1);
    }

    /**
     * 驼峰转下划线 map.key--> map.key
     *
     * @param map
     * @return
     */
    public static Map<String, Object> transform(Map<String, Object> map) {
        Map<String, Object> newMap = new HashMap<String, Object>();
        Iterator<Map.Entry<String, Object>> it = map.entrySet().iterator();
        while (it.hasNext()) {
            Map.Entry<String, Object> entry = it.next();
            String key = entry.getKey();
            String newKey = getTransformFieldName(key);
            if (entry.getValue() instanceof Map) {
                Map m = transform((Map) entry.getValue());
                newMap.put(newKey, m);
            } else if (entry.getValue() instanceof List) {
                List<Object> list = new ArrayList<>();
                for (Object obj : (List) entry.getValue()) {
                    if (obj instanceof Map) {
                        Map m = transform((Map) obj);
                        list.add(m);
                    } else {
                        list.add(obj);
                    }
                }
                newMap.put(newKey, list);
            } else {
                newMap.put(newKey, entry.getValue());
            }
        }
        return newMap;
    }


    /**
     * 下划线转驼峰
     *
     * @param map
     * @return
     */
    public static Map<String, Object> formatHumpName(Map<String, Object> map) {
        Map<String, Object> newMap = new HashMap<String, Object>();
        Iterator<Map.Entry<String, Object>> it = map.entrySet().iterator();
        while (it.hasNext()) {
            Map.Entry<String, Object> entry = it.next();
            String key = entry.getKey();
            String newKey = underlineToCamel(key);
            if (entry.getValue() instanceof Map) {
                Map m = formatHumpName((Map) entry.getValue());
                newMap.put(newKey, m);
            } else {
                newMap.put(newKey, entry.getValue());
            }
        }
        return newMap;
    }

    public static String underlineToCamel(String param) {
        if (param == null || "".equals(param.trim())) {
            return "";
        }
        int len = param.length();
        StringBuilder sb = new StringBuilder(len);
        for (int i = 0; i < len; i++) {
            char c = param.charAt(i);
            if (c == UNDERLINE) {
                if (++i < len) {
                    sb.append(Character.toUpperCase(param.charAt(i)));
                }
            } else {
                sb.append(param.charAt(i));
//                sb.append(Character.toLowerCase(param.charAt(i)));
            }
        }
        return sb.toString();
    }

//    public static void main(String[] args) {
//        WalletDto dto = new WalletDto();
//        dto.setAdjustType(123);
//        dto.setBin("1233e");
//        dto.setAdjustLimit(new BigDecimal(120.01));
//        Map transform = HumpTransformUnderlineUtils.transform(dto);
//        String jsonString = JSON.toJSONString(transform);
//        System.out.println(jsonString);
//        Map map = new HashMap();
//        map.put("adjust_type", new BigDecimal("123.11"));
//        map.put("adjustType1", new BigDecimal("123.11"));
//        Map map1 = new HashMap();
//        map1.put("adjust_type", new BigDecimal("123.99"));
//        map1.put("adjust_limit", new BigDecimal("123.1234567890987654321"));
//        map1.put("hash_map", map);
//        String str = JSON.toJSONString(map1);
//        Map map2 = JSON.parseObject(str, Map.class);
//        String str1 = JSON.toJSONString(formatHumpName(map2));
//
//        System.out.println(str1);
//        dto = JSON.parseObject(str1,WalletDto.class);
//        System.out.println(dto.toJSON());
//    }
}